//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////
//
//
// (C) Copyright 2007 Marvell International Ltd.
//  All Rights Reserved
//


#include "precomp.h"

void Reboot()
{
    // Flush the flash database volumes
    CeFlushDBVol(NULL);

    // Flush the registry to flash.
    RegFlushKey(HKEY_CURRENT_USER);

    KernelIoControl(IOCTL_HAL_REBOOT, NULL, NULL, NULL, 0, NULL);

    return;
}


//
// Thread responsible for monitoring RIL
//
DWORD WINAPI MonitorThreadProc(LPVOID lpParameter)
{
    TBD_FUNCTION(MonitorThreadProc);
#ifdef UNDER_CE
    DWORD dwWait;
    CMonitor* pMonitor = (CMonitor*)lpParameter;
    int nEventCnt = 2;

    TBD_ASSERT(NULL != pMonitor);

    // Let the main thead know that the thread has started up
    pMonitor->m_pCheckPoint->Reached();

    HANDLE rghEvents[] = { g_hCriticalErrorEvent, pMonitor->m_hCancelEvent };

    // Switch the thread into higher priority (to guarantee that CPM doesn't reboot the device just because this
    //    thread didn't get scheduled)
    if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
        goto Error;
    }

    while (1) {
        dwWait = WaitForMultipleObjects(nEventCnt, rghEvents, FALSE, INFINITE);
        if (WAIT_OBJECT_0 == dwWait) {
                // For platforms that do not use CPM, just reboot thank you
                TBD_OUTPUT(TBDCT_INFO, TBDOL_ERROR, TEXT("RIL: Critical error has occurred, rebooting system..."));
                Reboot();
        } else if (WAIT_OBJECT_0 + 1 == dwWait) {
            // RIL is exiting -- terminate this thread
            goto Error;
        }
    }

Error:
#endif // UNDER_CE

    return 0;
}


//
// Ctor
//
CMonitor::CMonitor()
: m_hCancelEvent(NULL),
  m_pCheckPoint(NULL),
  m_hMonitorThread(NULL)
{
    TBD_FUNCTION(CMonitor::CMonitor);
}


//
// Dtor
//
CMonitor::~CMonitor()
{
    TBD_FUNCTION(CMonitor::~CMonitor);

    // Destroy the monitor thread
    if (m_hMonitorThread)
    {
        // Wait for the monitor thread to terminate
        DWORD dwRes = WaitForSingleObject(m_hMonitorThread, 10000);
        if (WAIT_OBJECT_0 != dwRes)
        {
            // If the thread did not terminate, then maybe
            // the timeout is too short. Alert someone.
            ASSERT(0);

            // We could try to force the thread to terminate,
            // but it's probably not worth the risk. The monitor
            // thread does two things: notify CPM, and quit.
            // If the thread is stuck in CPM, then let's not
            // exacerbate the problem by killing a thread that
            // is executing CPM code.
        }

        // Close thread object
        (void)CloseHandle(m_hMonitorThread);
        m_hMonitorThread = NULL;
    }

    delete m_pCheckPoint;
    m_pCheckPoint = NULL;
}


//
// Initialisation
//
BOOL CMonitor::Init(const HANDLE hCancelEvent)
{
    TBD_FUNCTION(CMonitor::Init);
    TBD_ASSERT(NULL != hCancelEvent);
    TBD_ASSERT(NULL != g_hCriticalErrorEvent);

    BOOL fRet = FALSE;

#ifdef UNDER_CE
    RILRetailTrace((TEXT("RIL: CMonitor::Init.\n")));    

    m_hCancelEvent = hCancelEvent;

    // Create the thread checkpoint
    m_pCheckPoint = new CCheckPoint;
    if (!m_pCheckPoint || !m_pCheckPoint->Init(1)) {
        goto Error;
    }

    // Launch the monitor thread
    m_hMonitorThread = CreateThread(NULL, 0, MonitorThreadProc, (LPVOID)this, 0, NULL);
    if (!m_hMonitorThread) {
        goto Error;
    }

    // Wait until the thread starts up
    if (!m_pCheckPoint->Wait(30000)) {
        goto Error;
    }
    fRet = TRUE;

Error:
    delete m_pCheckPoint;
    m_pCheckPoint = NULL;

    if (!fRet) {
        if (m_hMonitorThread) {
            (void)CloseHandle(m_hMonitorThread);
            m_hMonitorThread = NULL;
        }
    }
#endif // UNDER_CE

    return fRet;
}

